﻿#pragma once
#include "array/Array.hpp"
#include "lang/Exception.h"

namespace yzrilyzr_io{
	EBCLASS(ByteConvert){
	private:
	static void checkIndex(yzrilyzr_array::ByteArray & buf, u_index offset, u_index siz){
		if(offset + siz > buf.length)throw yzrilyzr_lang::EOFException();
	}
	public:
	static int16_t getShort(yzrilyzr_array::ByteArray & buf, u_index offset, bool bigEndian){
		int16_t v=0;
		u_index siz=sizeof(v);
		checkIndex(buf, offset, siz);
		if(bigEndian){
			v|=((buf[0 + offset] & 0xff) << 8);
			v|=((buf[1 + offset] & 0xff) << 0);
		} else{
			v|=((buf[1 + offset] & 0xff) << 8);
			v|=((buf[0 + offset] & 0xff) << 0);
		}
		return v;
	}
	static uint16_t getUnsignedShort(yzrilyzr_array::ByteArray & buf, u_index offset, bool bigEndian){
		return getShort(buf, offset, bigEndian) & 0xffff;
	}
	static int32_t getInt(yzrilyzr_array::ByteArray & buf, u_index offset, bool bigEndian){
		int32_t v=0;
		u_index siz=sizeof(v);
		checkIndex(buf, offset, siz);
		if(bigEndian){
			v|=((buf[0 + offset] & 0xff) << 24);
			v|=((buf[1 + offset] & 0xff) << 16);
			v|=((buf[2 + offset] & 0xff) << 8);
			v|=((buf[3 + offset] & 0xff) << 0);
		} else{
			v|=((buf[3 + offset] & 0xff) << 24);
			v|=((buf[2 + offset] & 0xff) << 16);
			v|=((buf[1 + offset] & 0xff) << 8);
			v|=((buf[0 + offset] & 0xff) << 0);
		}
		return v;
	}
	static uint32_t getUnsignedInt(yzrilyzr_array::ByteArray & buf, u_index offset, bool bigEndian){
		return getInt(buf, offset, bigEndian) & 0xffffffff;
	}
	static int64_t getLong(yzrilyzr_array::ByteArray & buf, u_index offset, bool bigEndian){
		int64_t v=0;
		u_index siz=sizeof(v);
		checkIndex(buf, offset, siz);
		if(bigEndian){
			v|=(static_cast<uint64_t>(buf[0 + offset] & 0xff) << 56);
			v|=(static_cast<uint64_t>(buf[1 + offset] & 0xff) << 48);
			v|=(static_cast<uint64_t>(buf[2 + offset] & 0xff) << 40);
			v|=(static_cast<uint64_t>(buf[3 + offset] & 0xff) << 32);
			v|=(static_cast<uint64_t>(buf[4 + offset] & 0xff) << 24);
			v|=(static_cast<uint64_t>(buf[5 + offset] & 0xff) << 16);
			v|=(static_cast<uint64_t>(buf[6 + offset] & 0xff) << 8);
			v|=(static_cast<uint64_t>(buf[7 + offset] & 0xff) << 0);
		} else{
			v|=(static_cast<uint64_t>(buf[7 + offset] & 0xff) << 56);
			v|=(static_cast<uint64_t>(buf[6 + offset] & 0xff) << 48);
			v|=(static_cast<uint64_t>(buf[5 + offset] & 0xff) << 40);
			v|=(static_cast<uint64_t>(buf[4 + offset] & 0xff) << 32);
			v|=(static_cast<uint64_t>(buf[3 + offset] & 0xff) << 24);
			v|=(static_cast<uint64_t>(buf[2 + offset] & 0xff) << 16);
			v|=(static_cast<uint64_t>(buf[1 + offset] & 0xff) << 8);
			v|=(static_cast<uint64_t>(buf[0 + offset] & 0xff) << 0);
		}
		return v;
	}
	static uint64_t getUnsignedLong(yzrilyzr_array::ByteArray & buf, u_index offset, bool bigEndian){
		return getLong(buf, offset, bigEndian) & 0xffffffffffffffff;
	}
	static float getFloat(yzrilyzr_array::ByteArray & buf, u_index offset, bool bigEndian){
		uint32_t v=getUnsignedInt(buf, offset, bigEndian);
		float v2=0;
		memcpy(&v2, &v, 4);
		return v2;
	}
	static double getDouble(yzrilyzr_array::ByteArray & buf, u_index offset, bool bigEndian){
		uint64_t v=getUnsignedLong(buf, offset, bigEndian);
		double v2=0;
		memcpy(&v2, &v, 8);
		return v2;
	}
	static void putShort(yzrilyzr_array::ByteArray & buf, u_index offset, int16_t v, bool bigEndian){
		putUnsignedShort(buf, offset, v & 0xffff, bigEndian);
	}
	static void putUnsignedShort(yzrilyzr_array::ByteArray & buf, u_index offset, uint16_t v, bool bigEndian){
		u_index siz=sizeof(v);
		checkIndex(buf, offset, siz);
		if(bigEndian){
			buf[0 + offset]=static_cast<int8_t>((v >> 8) & 0xff);
			buf[1 + offset]=static_cast<int8_t>((v >> 0) & 0xff);
		} else{
			buf[1 + offset]=static_cast<int8_t>((v >> 8) & 0xff);
			buf[0 + offset]=static_cast<int8_t>((v >> 0) & 0xff);
		}
	}
	static void putInt(yzrilyzr_array::ByteArray & buf, u_index offset, int32_t v, bool bigEndian){
		putUnsignedInt(buf, offset, v & 0xffffffff, bigEndian);
	}
	static void putUnsignedInt(yzrilyzr_array::ByteArray & buf, u_index offset, uint32_t v, bool bigEndian){
		u_index siz=sizeof(v);
		checkIndex(buf, offset, siz);
		if(bigEndian){
			buf[0 + offset]=static_cast<int8_t>((v >> 24) & 0xff);
			buf[1 + offset]=static_cast<int8_t>((v >> 16) & 0xff);
			buf[2 + offset]=static_cast<int8_t>((v >> 8) & 0xff);
			buf[3 + offset]=static_cast<int8_t>((v >> 0) & 0xff);
		} else{
			buf[3 + offset]=static_cast<int8_t>((v >> 24) & 0xff);
			buf[2 + offset]=static_cast<int8_t>((v >> 16) & 0xff);
			buf[1 + offset]=static_cast<int8_t>((v >> 8) & 0xff);
			buf[0 + offset]=static_cast<int8_t>((v >> 0) & 0xff);
		}
	}
	static void putLong(yzrilyzr_array::ByteArray & buf, u_index offset, int64_t v, bool bigEndian){
		putUnsignedLong(buf, offset, v & 0xffffffffffffffff, bigEndian);
	}
	static void putUnsignedLong(yzrilyzr_array::ByteArray & buf, u_index offset, uint64_t v, bool bigEndian){
		u_index siz=sizeof(v);
		checkIndex(buf, offset, siz);
		if(bigEndian){
			buf[0 + offset]=static_cast<int8_t>((v >> 56) & 0xff);
			buf[1 + offset]=static_cast<int8_t>((v >> 48) & 0xff);
			buf[2 + offset]=static_cast<int8_t>((v >> 40) & 0xff);
			buf[3 + offset]=static_cast<int8_t>((v >> 32) & 0xff);
			buf[4 + offset]=static_cast<int8_t>((v >> 24) & 0xff);
			buf[5 + offset]=static_cast<int8_t>((v >> 16) & 0xff);
			buf[6 + offset]=static_cast<int8_t>((v >> 8) & 0xff);
			buf[7 + offset]=static_cast<int8_t>((v >> 0) & 0xff);
		} else{
			buf[7 + offset]=static_cast<int8_t>((v >> 56) & 0xff);
			buf[6 + offset]=static_cast<int8_t>((v >> 48) & 0xff);
			buf[5 + offset]=static_cast<int8_t>((v >> 40) & 0xff);
			buf[4 + offset]=static_cast<int8_t>((v >> 32) & 0xff);
			buf[3 + offset]=static_cast<int8_t>((v >> 24) & 0xff);
			buf[2 + offset]=static_cast<int8_t>((v >> 16) & 0xff);
			buf[1 + offset]=static_cast<int8_t>((v >> 8) & 0xff);
			buf[0 + offset]=static_cast<int8_t>((v >> 0) & 0xff);
		}
	}
	static void putFloat(yzrilyzr_array::ByteArray & buf, u_index offset, float v, bool bigEndian){
		uint32_t b=0;
		memcpy(&b, &v, 4);
		putUnsignedInt(buf, offset, b, bigEndian);
	}
	static void putDouble(yzrilyzr_array::ByteArray & buf, u_index offset, double v, bool bigEndian){
		uint64_t b=0;
		memcpy(&b, &v, 8);
		putUnsignedLong(buf, offset, b, bigEndian);
	}
	};
}